package com.guigu.servicegoods.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.guigu.common_util.pojo.config.CacheKey;
import com.guigu.servicegoods.domain.TbSku;
import com.guigu.servicegoods.service.SkuSearchService;
import com.guigu.servicegoods.service.TbSkuService;
import org.apache.http.HttpHost;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.*;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;

@Service
public class SkuSearchServiceImpl implements SkuSearchService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private TbSkuService skuService;

    @Autowired
    private RestHighLevelClient restHighLevelClient;


    @Override
    public Map search(Map<String, String> searchMap) {
        // 封装请求的对象
        SearchRequest searchRequest = new SearchRequest("my_sku12");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 创建bool类型的条件构造器
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        // 1.1关键字搜索
        MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("name", searchMap.get("keywords"));
        boolQueryBuilder.must(matchQueryBuilder);


        if(searchMap.get("category")!=null){
            TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("categoryName", searchMap.get("category"));
            boolQueryBuilder.filter(termQueryBuilder);
        }

        //设置高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("name").preTags("<font style='color:red'>").postTags("</font>");
        searchSourceBuilder.highlighter(highlightBuilder);

        // 1.2 聚合查询（商品分类）
        TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms("sku_category").field("categoryName");
        searchSourceBuilder.aggregation(termsAggregationBuilder);

        //1.3 品牌过滤
        if(searchMap.get("brand")!=null){
            TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("brandName", searchMap.get("brand"));
            boolQueryBuilder.filter(termQueryBuilder);
        }

        //1.4 规格过滤
        for(String key: searchMap.keySet() ){
            if( key.startsWith("spec.") ){//如果是规格参数
                TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery(key+".keyword", searchMap.get(key).replace(" ","+"));
                boolQueryBuilder.filter(termQueryBuilder);
            }
        }

        //1.5 价格过滤
        if(searchMap.get("price")!=null ){
            String[] price = searchMap.get("price").split("-");
            if(!price[0].equals("0")){ //最低价格不等于0
                RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("price").gte(price[0] + "00");
                boolQueryBuilder.filter(rangeQueryBuilder);
            }
            if(!price[1].equals("*")){ //如果价格由上限
                RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("price").lte(price[1] + "00");
                boolQueryBuilder.filter(rangeQueryBuilder);
            }
        }

        // 分页
        Integer pageNo = Integer.parseInt(searchMap.get("pageNo")); // 页码
        Integer pageSize = 30; // 页大小

        // 起始记录下标
        int fromIndex = (pageNo - 1) * pageSize;
        searchSourceBuilder.from(fromIndex);
        searchSourceBuilder.size(pageSize);

        // 排序
        String sort = searchMap.get("sort");//排序字段
        String sortOrder = searchMap.get("sortOrder");//排序规则
        if(!"".equals(sort)){
            searchSourceBuilder.sort(sort, SortOrder.valueOf(sortOrder));
        }

        searchSourceBuilder.query(boolQueryBuilder);
        searchRequest.source(searchSourceBuilder);
        //3. 获取请求结果
        SearchResponse searchResponse = null;

        // 封装查询结果
        Map resultMap = new HashMap();
        try {
            // 搜索
            searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            SearchHits searchHits = searchResponse.getHits();
            SearchHit[] hits = searchHits.getHits();

            // 保存商品列表的集合
            List<Map<String, Object>> skuList = new ArrayList<>();
            for(SearchHit hit: hits) {
                Map<String, Object> skuMap = hit.getSourceAsMap();
                //name高亮处理
                Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                HighlightField name = highlightFields.get("name");
                Text[] fragments = name.fragments();
                skuMap.put("id",hit.getId());
                skuMap.put("name",fragments[0].toString());//用高亮的内容替换原内容
                skuList.add(skuMap);
            }
            resultMap.put("rows", skuList);

            //2.2 商品分类列表
            Aggregations aggregations = searchResponse.getAggregations();
            Map<String, Aggregation> aggregationMap = aggregations.getAsMap();
            Terms terms = (Terms) aggregationMap.get("sku_category");
            List<? extends Terms.Bucket> buckets = terms.getBuckets();
            List<String> categoryList=new ArrayList();
            for( Terms.Bucket bucket:buckets ){
                categoryList.add(bucket.getKeyAsString());
            }
            resultMap.put("categoryList",categoryList);

            //2.3 品牌列表
            String categoryName="";//商品分类名称
            if(searchMap.get("category")==null){ // 如果没有分类条件
                if(categoryList.size()>0){
                    categoryName=categoryList.get(0);//提取分类列表的第一个分类
                }
            }else{
                categoryName=searchMap.get("category");//取出参数中的分类
            }
            if (searchMap.get("brand")==null) {
                List<Map> brandList = (List<Map>) redisTemplate.boundHashOps(CacheKey.CATEGORY_BRAND).get(categoryName);
                // 查询品牌列表
                resultMap.put("brandList",brandList);
            }
            //2.4 规格列表
            List<Map> specList = (List<Map>) redisTemplate.boundHashOps(CacheKey.CATEGORY_SPEC).get(categoryName);//规格列表
            if (specList != null) {
                for(Map spec:specList){
                    String[] options = ((String) spec.get("options")).split(",");//规格选项列表
                    spec.put("options",options);
                }
            }

            resultMap.put("specList",specList);
            // 2.5 页码    计算总页数
            long totalCount = searchHits.getTotalHits(); // 总记录数
            long pageCount = (totalCount % pageSize == 0) ? totalCount / pageSize : (totalCount / pageSize + 1);
            resultMap.put("totalPages",pageCount);


        } catch (IOException e) {
            e.printStackTrace();
        }
        return resultMap;
    }


    /*-----------------------------------------------------------------------------------------*/


    @RabbitListener(queues = "queue.sjsy")
    public void findBySpu(Message message) {
        System.out.println("执行了上架添加索引库");
        String id = new String(message.getBody());
        QueryWrapper<TbSku> wrapper = new QueryWrapper<>();
        wrapper.eq("spu_id",id);
        List<TbSku> skuList = skuService.list(wrapper);
        // 1.连接Rest接口
        HttpHost http = new HttpHost("127.0.0.1", 9200, "http");
        RestClientBuilder restClientBuilder = RestClient.builder(http).setMaxRetryTimeoutMillis(1000*60*10); //rest构建器
        RestHighLevelClient restHighLevelClient = new RestHighLevelClient(restClientBuilder); //高级客户端对象（连接）

        //2. 封装请求的对象
        BulkRequest bulkRequest = new BulkRequest();
        for(TbSku sku: skuList){
            redisTemplate.boundHashOps(CacheKey.SKU_PRICE).put(sku.getId(),sku.getPrice());
            IndexRequest indexRequest = new IndexRequest("my_sku12", "doc", sku.getId());
            Map skuMap = new HashMap<>();
            skuMap.put("name",sku.getName());
            skuMap.put("brandName",sku.getBrandName());
            skuMap.put("categoryName",sku.getCategoryName());
            skuMap.put("price",sku.getPrice());
            skuMap.put("image", sku.getImage());
            skuMap.put("spuId", sku.getSpuId());
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            Date createTime = sku.getCreateTime();
            if(createTime!=null)
                skuMap.put("createTime", sdf.format(sku.getCreateTime()));
            else
                skuMap.put("createTime", null);
            skuMap.put("saleNum", sku.getSaleNum());
            skuMap.put("commentNum", sku.getCommentNum());

            Map<String, String> spec = JSON.parseObject(sku.getSpec(), Map.class);
            skuMap.put("spec",spec);
            indexRequest.source(skuMap);

            bulkRequest.add(indexRequest);
        }
        //3. 获取请求结果
        try {
            BulkResponse bulkResponse = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
            int status = bulkResponse.status().getStatus();
            System.out.println(status);
            restHighLevelClient.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }




    @RabbitListener(queues = "queue.xjsy")
    public void removeBySku(Message message) throws IOException {
        System.out.println("执行了下架删除索引库");
        String id = new String(message.getBody());
        // 1.连接Rest接口
        HttpHost http = new HttpHost("127.0.0.1", 9200, "http");
        RestClientBuilder restClientBuilder = RestClient.builder(http).setMaxRetryTimeoutMillis(1000*60*10); //rest构建器
        RestHighLevelClient restHighLevelClient = new RestHighLevelClient(restClientBuilder); //高级客户端对象（连接）

        DeleteByQueryRequest deleteRequest=new DeleteByQueryRequest ("my_sku12");
        deleteRequest.setDocTypes("doc"); //设置查询的类型
        deleteRequest.setQuery(new TermQueryBuilder("spuId",id));

        BulkByScrollResponse response = restHighLevelClient.deleteByQuery(deleteRequest,RequestOptions.DEFAULT);
    }

}
